/*
 * This file is part of aion-unique <aion-unique.org>.
 *
 *  aion-unique is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  aion-unique is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with aion-unique.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.aionemu.gameserver.services;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;

import com.aionemu.commons.utils.Rnd;
import com.aionemu.gameserver.configs.main.EnchantsConfig;
import com.aionemu.gameserver.model.DescriptionId;
import com.aionemu.gameserver.model.gameobjects.Item;
import com.aionemu.gameserver.model.gameobjects.PersistentState;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.gameobjects.stats.StatEnum;
import com.aionemu.gameserver.model.gameobjects.stats.listeners.ItemEquipmentListener;
import com.aionemu.gameserver.model.gameobjects.stats.modifiers.EnchantModifier;
import com.aionemu.gameserver.model.gameobjects.stats.modifiers.StatModifier;
import com.aionemu.gameserver.model.items.ItemSlot;
import com.aionemu.gameserver.model.items.ManaStone;
import com.aionemu.gameserver.model.templates.item.ArmorType;
import com.aionemu.gameserver.model.templates.item.ItemQuality;
import com.aionemu.gameserver.model.templates.item.ItemTemplate;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.network.aion.serverpackets.SM_UPDATE_ITEM;
import com.aionemu.gameserver.utils.PacketSendUtility;

/**
 * @author ATracer
 * 
 */
public class EnchantService
{
	private static final Logger	log	= Logger.getLogger(EnchantService.class);

	/**
	 * @param player
	 * @param targetItem
	 * @param parentItem
	 */
	public static void breakItem(Player player, Item targetItem, Item parentItem)
	{

		ItemTemplate itemTemplate = targetItem.getItemTemplate();
		ItemQuality quality = itemTemplate.getItemQuality();

		int number = 0;
		int level = 0;
		switch (quality)
		{
			case COMMON:
			case JUNK:
				number = Rnd.get(1, 2);
				level = Rnd.get(0, 5);
				break;
			case RARE:
				number = Rnd.get(1, 3);
				level = Rnd.get(0, 10);
				break;
			case LEGEND:
			case MYTHIC:
				number = Rnd.get(1, 3);
				level = Rnd.get(0, 15);
				break;
			case EPIC:
			case UNIQUE:
				number = Rnd.get(1, 3);
				level = Rnd.get(0, 20);
				break;
		}

		int enchantItemLevel = targetItem.getItemTemplate().getLevel() + level;
		int enchantItemId = 166000000 + enchantItemLevel;
		if (!Item.removeItemFromInventory(player, targetItem))
		{
			log.info("[AUDIT]BreakItem exploit. Target item not in player: "+player.getName());
			return;
		}
		if (Item.decreaseItemCount(player, parentItem, 1)!= 0)
		{
			log.info("[AUDIT]BreakItem exploit. Extract tool not in player: "+player.getName());
			return;
		}

		Item.addItem(player, enchantItemId, number);
	}

	/**
	 * @param player
	 * @param parentItem
	 * @param targetItem
	 */
	public static boolean enchantItem(Player player, Item parentItem, Item targetItem, Item supplementItem, int supplementUseCount)
	{
		int enchantStoneLevel = parentItem.getItemTemplate().getLevel();
		int targetItemLevel = targetItem.getItemTemplate().getLevel();

		if (targetItem.getEquipmentSlot() == ItemSlot.MAIN_SUB_HAND.getSlotIdMask() || targetItem.getEquipmentSlot() == ItemSlot.OFF_SUB_HAND.getSlotIdMask())
		{
			log.info("[AUDIT]Enchant exploit. Enchant sub weapon "+player.getName());
			return false;
		}

		if (targetItemLevel > enchantStoneLevel)
			return false;

		int qualityCap = 0;

		ItemQuality quality = targetItem.getItemTemplate().getItemQuality();

		switch (quality)
		{
			case COMMON:
			case JUNK:
				qualityCap = 0;
				break;
			case RARE:
				qualityCap = 5;
				break;
			case LEGEND:
			case MYTHIC:
				qualityCap = 10;
				break;
			case EPIC:
			case UNIQUE:
				qualityCap = 15;
				break;
		}

		int success = 50;

		int levelDiff = enchantStoneLevel - targetItemLevel;

		int extraSuccess = levelDiff - qualityCap;
		success += (extraSuccess * 5);

		if (supplementItem != null)
		{
			int addsuccessRate = 10;
			int supplementId = supplementItem.getItemId();

			switch (supplementId)
			{
				//lesser supplements
				case 166100000:
				case 166100003:
				case 166100006:
					addsuccessRate = EnchantsConfig.LSUP;
					break;

				//supplements
				case 166100001:
				case 166100004:
				case 166100007:
					addsuccessRate = EnchantsConfig.RSUP;
					break;

				//greater supplements
				case 166100002:
				case 166100005:
				case 166100008:
					addsuccessRate = EnchantsConfig.GSUP;
					break;
			}

			if (!Item.decreaseItemCountByItemId(player, supplementItem.getItemId(), supplementUseCount))
			{
				log.info("[AUDIT]Enchant exploit. Low supplement item count. "+player.getName());
				return false;
			}

			//Add successRate
			success = success + addsuccessRate;
		}

		if (Item.decreaseItemCount(player, parentItem, 1) != 0)
		{
			log.info("[AUDIT]Enchant exploit. Low enchant stone count "+player.getName());
			return false;
		}

		if (success > 95)
			success = 95;

		boolean result = false;

		if (Rnd.get(0, 100) < success)
			result = true;

		int currentEnchant = targetItem.getEnchantLevel();

		if (!result)
		{
			// Retail: http://powerwiki.na.aiononline.com/aion/Patch+Notes:+1.9.0.1
			// When socketing fails at +11~+15, the value falls back to +10.
			if (currentEnchant > 10)
				currentEnchant = 10;
			else if (currentEnchant > 0)
				currentEnchant -= 1;
		}
		else
		{
			// Items that are Fabled or Eternal can get up to +15.
			ItemQuality targetQuality = targetItem.getItemTemplate().getItemQuality();
			if (targetQuality == ItemQuality.UNIQUE || targetQuality == ItemQuality.EPIC)
			{
				if (currentEnchant < 15)
					currentEnchant += 1;
			}
			else
			{
				if (currentEnchant < 10)
					currentEnchant += 1;
			}
		}

		targetItem.setEnchantLevel(currentEnchant);
		if (targetItem.isEquipped())
			player.updatePlayerStat();
		
		PacketSendUtility.sendPacket(player, new SM_UPDATE_ITEM(targetItem));

		if (targetItem.isEquipped())
			player.getEquipment().setPersistentState(PersistentState.UPDATE_REQUIRED);
		else
			player.getInventory().setPersistentState(PersistentState.UPDATE_REQUIRED);

		if (result)
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_ENCHANT_ITEM_SUCCEED(new DescriptionId(Integer.parseInt(targetItem.getName()))));
		}
		else
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_ENCHANT_ITEM_FAILED(new DescriptionId(Integer.parseInt(targetItem.getName()))));
		}

		return result;
	}

	/**
	 * @param player
	 * @param parentItem
	 * @param targetItem
	 */
	public static boolean socketManastone(Player player, Item parentItem, Item targetItem, Item supplementItem, int supplementUseCount, boolean fusionSlot)
	{
		boolean result = false;
		int successRate = 76;
		Set<ManaStone> manastones;
		if (fusionSlot)
			manastones = targetItem.getFusionStones();
		else
			manastones = targetItem.getItemStones();
		int stoneCount = manastones.size();
		if (targetItem.getSockets(fusionSlot) <= stoneCount)
		{
			log.info("[AUDIT] Client hack Manastone socket count full!!!"+player.getName());
			return false;
		}
		if (targetItem.getEquipmentSlot() == ItemSlot.MAIN_SUB_HAND.getSlotIdMask() || targetItem.getEquipmentSlot() == ItemSlot.OFF_SUB_HAND.getSlotIdMask())		{
			log.info("[AUDIT] Enchant exploit: Enchant sub weapon!"+player.getName());
			return false;
		}
		switch (stoneCount)
		{
			case 1:
				successRate = EnchantsConfig.MSPERCENT;
				break;
			case 2:
				successRate = EnchantsConfig.MSPERCENT1;
				break;
			case 3:
				successRate = EnchantsConfig.MSPERCENT2;
				break;
			case 4:
				successRate = EnchantsConfig.MSPERCENT3;
				break;
			case 5:
				successRate = EnchantsConfig.MSPERCENT4;
				break;
		}

		if (stoneCount >= 6)
			successRate = EnchantsConfig.MSPERCENT5;

		if (supplementItem != null)
		{
			int addsuccessRate = 10;
			int supplementId = supplementItem.getItemTemplate().getTemplateId();
			int manastoneCount = stoneCount + 1;

			//lesser supplements
			if (supplementId == 166100000 || supplementId == 166100003 || supplementId == 166100006)
				addsuccessRate = 10;
			//supplements
			if (supplementId == 166100001 || supplementId == 166100004 || supplementId == 166100007)
				addsuccessRate = 15;
			//greater supplements
			if (supplementId == 166100002 || supplementId == 166100005 || supplementId == 166100008)
				addsuccessRate = 20;

			//supplementUseCount * manastoneCount
			if (stoneCount > 0)
				supplementUseCount = supplementUseCount * manastoneCount;

			if (Item.decreaseItemCount(player, supplementItem, supplementUseCount) != 0)
				return false;

			//Add successRate
			successRate = successRate + addsuccessRate;
		}
		if (Item.decreaseItemCount(player, parentItem, 1) != 0)
			return false;
		if (Rnd.get(0, 100) < successRate)
			result = true;
		if (result)
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_GIVE_ITEM_OPTION_SUCCEED(new DescriptionId(Integer.parseInt(targetItem.getName()))));
			ManaStone manaStone = Item.addManaStone(targetItem, parentItem.getItemTemplate().getTemplateId(), fusionSlot);
			if (targetItem.isEquipped() && targetItem.getEquipmentSlot() != ItemSlot.MAIN_SUB_HAND.getSlotIdMask() && targetItem.getEquipmentSlot() != ItemSlot.OFF_SUB_HAND.getSlotIdMask())
			{
				ItemEquipmentListener.addStoneStats(manaStone, player.getGameStats(), targetItem);
			}
		}
		else
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_GIVE_ITEM_OPTION_FAILED(new DescriptionId(Integer.parseInt(targetItem.getName()))));
			Set<ManaStone> manaStones;
			if (fusionSlot)
				manaStones = targetItem.getFusionStones();
			else
				manaStones = targetItem.getItemStones();
			if (targetItem.isEquipped())
			{
				ItemEquipmentListener.removeStoneStats(manaStones, player.getGameStats());
			}
			Item.removeAllManastone(player, targetItem, fusionSlot);
		}

		PacketSendUtility.sendPacket(player, new SM_UPDATE_ITEM(targetItem));
		return result;
	}

	/**
	 * 
	 * @param player
	 * @param item
	 */
	public static void onItemEquip(Player player, Item item)
	{
		List <StatModifier> modifiers = new ArrayList<StatModifier>();
		try
		{
			if (item.getItemTemplate().isWeapon())
			{
				switch (item.getItemTemplate().getWeaponType())
				{
					case BOOK_2H:
					case ORB_2H:
						modifiers.add(new EnchantModifier(item, StatEnum.BOOST_MAGICAL_SKILL));
						modifiers.add(new EnchantModifier(item, StatEnum.MAGICAL_ATTACK));
						break;
					case MACE_1H:
					case STAFF_2H:
						modifiers.add(new EnchantModifier(item, StatEnum.BOOST_MAGICAL_SKILL));
					case DAGGER_1H:
					case BOW:
					case POLEARM_2H:
					case SWORD_1H:
					case SWORD_2H:
						if (item.getEquipmentSlot() == ItemSlot.MAIN_HAND.getSlotIdMask())
							modifiers.add(new EnchantModifier(item, StatEnum.PHYSICAL_ATTACK_MAIN_HAND));
						else
							modifiers.add(new EnchantModifier(item, StatEnum.PHYSICAL_ATTACK_OFF_HAND));
				}
			}
			else if (item.getItemTemplate().isArmor())
			{
				if (item.getItemTemplate().getArmorType() == ArmorType.SHIELD)
				{
					modifiers.add(new EnchantModifier(item, StatEnum.DAMAGE_REDUCE));
					modifiers.add(new EnchantModifier(item, StatEnum.BLOCK));
				}
				else
				{
					modifiers.add(new EnchantModifier(item, StatEnum.PHYSICAL_DEFENSE));
					modifiers.add(new EnchantModifier(item, StatEnum.MAXHP));
					modifiers.add(new EnchantModifier(item, StatEnum.CRITICAL_RESIST));
				}
			}
			if (!modifiers.isEmpty())
				player.getGameStats().addModifiers(item, modifiers);
		}
		catch (Exception ex)
		{
			log.error("Error on item equip.", ex);
		}
	}
}